package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;

import com.livestocksolutions.LivestockSolutions;
import javax.swing.JComboBox;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileSystemView;

/**
 * Show the progress of the Synchronisation to Android activity to the user.
 * @author Ken DeVries
 * @author Adam Parr
 * 
 * @.modified 24 October 2012
 */
public class SynchronizeFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	private final JProgressBar syncProgress = new JProgressBar();
	private final JPanel southButtonPanel = new JPanel();
	private final JButton closeWindow = new JButton("Close");
	
	/**
	 * This Synchronisation process is currently only compatible with devices
	 *	that use <b>USB Mass Storage</b> as opposed to <b>MTP</b> to connect to
	 *	a Computer. As the process to connect an Android device may not be the
	 *	same on different devices, please refer to your Android Devices user
	 *	manual to determine if your device is compatible
	 */
	private final JLabel syncLabel = new JLabel("<html><body>" +
		"This Synchronisation process is currently only compatible with devices that use <b>USB Mass Storage</b><br>" +
		"as opposed to <b>Media Transfer Protocol (MTP)</b> to connect to a Computer.<br><br>" +
		"As the process to connect to an Android device may different across devices, please refer to your Android<br>" +
		"Devices user manual to determine if your device is compatible.<br>" +
		"</body></html>");
	
	/**
	 * MTP assistance instructions.<br>
	 * If your device uses <b>MTP</b>. Please see the documentation for step by step instructions.<br><br>
	 * You may need to turn on <b>USB Mass Storage</b> on your Android Device, please refer to your<br>
	  "devices documentation for instructions on turning on <b>USB Mass Storage</b>.
	 */
	private final JLabel mtpLabel = new JLabel("<html><body>" +
	  "If your device uses <b>MTP</b>, please see the documentation for step by step instructions.<br><br>" +
	  "You may need to turn on <b>USB Mass Storage</b> on your Android Device, please refer to your<br>" +
	  "devices documentation for instructions on turning on <b>USB Mass Storage</b>." +
	  "</body></html>");
	
	
	private boolean running=true;
	private boolean success=false;
	
	private JPanel panel = new JPanel();
	
	private ArrayList<String> drivePaths = new ArrayList<String>();
	/**
	 * Constructor.
	 */
	public SynchronizeFrame(){
		panel.setBorder(new EmptyBorder(5,5,5,5));
		panel.setLayout(new BorderLayout(0,0));
		add(panel);
		setTitle("Synchronise data between Android device and PC");
		setIconImage(MainFrame.getImage(MainFrame.APP_ICON));
		syncLabel.setHorizontalAlignment(SwingConstants.CENTER);
		mtpLabel.setHorizontalAlignment(SwingConstants.CENTER);
		
		panel.add(syncLabel, BorderLayout.NORTH);
		
		final JPanel driveSelectPanel = new JPanel();
		panel.add(driveSelectPanel, BorderLayout.CENTER);
		driveSelectPanel.setLayout(new BorderLayout(0, 0));
		JPanel driveListPanel = new JPanel();
		
		
		JLabel lblDrive = new JLabel("Select the location of the Android device");
		final JComboBox driveSelection = new JComboBox();
		JButton btnDriveRefresh = new JButton("Refresh");
		
		final JButton startBtn = new JButton("Start");

		btnDriveRefresh.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event){
				int selected = -1;
				driveSelection.removeAllItems();
				drivePaths=new ArrayList<String>();
				try {
					driveSelection.addItem("Not in list");
					drivePaths.add("");
					if (System.getProperty("os.name").toLowerCase().contains("win")){
						// Assume Windows.
						for(File f : File.listRoots()){
							if(f.canRead() && f.canWrite()){
								driveSelection.addItem(FileSystemView.getFileSystemView().getSystemDisplayName(f)+(!f.getName().equals("")?" ("+f.getName()+")":""));
								drivePaths.add(f.getAbsolutePath());
								// Look inside to see if it contains the "Livestock Solutions" folder
								try{
									if(f.list(new FilenameFilter(){@Override public boolean accept(File dir, String name) {return name.toLowerCase().equals("livestock solutions");
										}}).length == 1){
										selected=driveSelection.getItemCount()-1;
										driveSelection.setSelectedIndex(selected);
									}
								}catch(NullPointerException e){}
							}
						}
					}else{
						// Look for drives mounted in "/mnt/" and "/media/"
						for(File f : new File("/mnt/").listFiles(new FilenameFilter(){
							@Override
							public boolean accept(File dir, String name) {
								File drive = new File(dir,name);
								if(drive.isDirectory() && drive.getFreeSpace()!=dir.getFreeSpace()){
									return true;
								}
								return false;
							}
						})){
							driveSelection.addItem(FileSystemView.getFileSystemView().getSystemDisplayName(f)+" ("+f.getName()+")");
							drivePaths.add(f.getAbsolutePath());
							// Look inside to see if it contains the "Livestock Solutions" folder
							if(f.list(new FilenameFilter(){
								@Override
								public boolean accept(File dir, String name) {
									return name.toLowerCase().equals("livestock solutions")?true:false;
								}
								
							}).length == 1){
								selected=driveSelection.getItemCount()-1;
								driveSelection.setSelectedIndex(selected);
							}
						}
						
						for(File f : new File("/media/").listFiles(new FilenameFilter(){
							@Override
							public boolean accept(File dir, String name) {
								File drive = new File(dir,name);
								if(drive.isDirectory() && drive.getFreeSpace()!=dir.getFreeSpace()){
									return true;
								}
								return false;
							}
						})){
							driveSelection.addItem(FileSystemView.getFileSystemView().getSystemDisplayName(f)+" ("+f.getName()+")");
							drivePaths.add(f.getAbsolutePath());
							// Look inside to see if it contains the "Livestock Solutions" folder
							if(f.list(new FilenameFilter(){
								@Override
								public boolean accept(File dir, String name) {
									return name.toLowerCase().equals("livestock solutions")?true:false;
								}
								
							}).length == 1){
								selected=driveSelection.getItemCount()-1;
								driveSelection.setSelectedIndex(selected);
							}
						}
					}
				
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				if(LivestockSolutions.getLastSyncPath()!=null&&!LivestockSolutions.getLastSyncPath().equals("")){
					driveSelection.addItem("Last Used");
					drivePaths.add(LivestockSolutions.getLastSyncPath());
					if(selected==-1){
						selected=driveSelection.getItemCount()-1;
						driveSelection.setSelectedIndex(selected);
					}
				}
			}
		});

		btnDriveRefresh.doClick();
		
		driveSelection.addItemListener(new ItemListener(){
			@Override
			public void itemStateChanged(ItemEvent e) {
				if(drivePaths.size()>0&&driveSelection.getSelectedIndex()>=0){
					if(drivePaths.get(driveSelection.getSelectedIndex()).equals("")){
						startBtn.setEnabled(false);
						// Show the MTP message
						driveSelectPanel.add(mtpLabel, BorderLayout.CENTER);
						pack();
						setLocationRelativeTo(null);
					}else{
						startBtn.setEnabled(true);
						driveSelectPanel.remove(mtpLabel);
						pack();
						setLocationRelativeTo(null);
					}
				}
			}
		});
		
		if(driveSelection.getSelectedIndex()==0){
			startBtn.setEnabled(false);
			// Show the MTP message
			driveSelectPanel.add(mtpLabel, BorderLayout.CENTER);
		}
		
		setTitle("Backup");
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		
		driveListPanel.add(lblDrive);
		driveListPanel.add(driveSelection);
		driveListPanel.add(btnDriveRefresh);
		driveSelectPanel.add(driveListPanel, BorderLayout.NORTH);
		
		setSize(300,100);
		setMinimumSize(new Dimension(300,100));
		
		startBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e){
				LivestockSolutions.setSyncLocation(drivePaths.get(driveSelection.getSelectedIndex()));
				System.out.println(drivePaths.get(driveSelection.getSelectedIndex()));
				remove(driveSelectPanel);
				setVisible(false);
				start();
			}
		});
		
		JButton newLocBtn = new JButton("Specify Different Location");
		newLocBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e){
				setVisible(false);
				start(true);
			}
		});
		
		JPanel startPnl = new JPanel();
		startPnl.add(startBtn, BorderLayout.CENTER);
		JPanel newLocPnl = new JPanel();
		newLocPnl.add(newLocBtn, BorderLayout.CENTER);
		southButtonPanel.add(startPnl);
		southButtonPanel.add(newLocPnl);
		
		panel.add(southButtonPanel, BorderLayout.SOUTH);
		pack();
		setLocationRelativeTo(null);
	}
	
	/**
	 * Start the Backup/Restore action and display progress and any errors to the user.
	 */
	public void start(){
		start(false);
	}
	
	/**
	 * Start the Backup/Restore action and display progress and any errors to the user.
	 * @param chooseSyncPath <tt>true</tt> always show a dialogue window to let the user
	 *                        choose where to sync to/from. <tt>false</tt>, let the system decide.
	 */
	public void start(boolean chooseSyncPath){
		running=true;
		panel.remove(southButtonPanel);
		panel.add(syncProgress, BorderLayout.SOUTH);
		syncLabel.setText("Preparing to Sync...");
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
		syncProgress.setIndeterminate(true);
		syncProgress.setValue(0);
		String syncPath=LivestockSolutions.getLastSyncPath();
		if(syncPath==null || (!new File(syncPath).exists() || !new File(syncPath).canWrite()) || chooseSyncPath){
			JFileChooser jfc = new JFileChooser();
			if(syncPath!=null){
				File f = new File(syncPath);
				jfc.setCurrentDirectory(f);
				jfc.setSelectedFile(f);
			}
			jfc.setAcceptAllFileFilterUsed(false);
			jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
			jfc.setDialogTitle("Please select the location of the Android Device");
			if(jfc.showOpenDialog(this)==JFileChooser.APPROVE_OPTION){
				syncPath=jfc.getSelectedFile().getAbsolutePath();
			}else{
				dispose();
				return;
			}
		}
		if(syncPath!=null){
			new Thread(){
				@Override
				public void run(){
					while(running){
						try {
							sleep(50);
						} catch (InterruptedException e) {}
						syncLabel.setText("Synchronising... ("+LivestockSolutions.getProgress()+"%)");
						syncProgress.setValue(LivestockSolutions.getProgress());
					}
					String result="";
					String afterRes="<br>For the changes to be visible on the Android Device,<br>please disconnect the device from the computer.";
					if(success){
						result="Synchronisation Successful<br>";
					}else{
						result="Synchronisation Failed<br>";
					}
					
					syncLabel.setText("<html><body style=\"text-align:center\">"+result+LivestockSolutions.getMessage()+afterRes+"</body></html>");

					panel.removeAll();
					panel.add(syncLabel, BorderLayout.NORTH);
					JPanel closePanel = new JPanel();
					closePanel.add(closeWindow, BorderLayout.CENTER);
					panel.add(closePanel, BorderLayout.SOUTH);
					pack();

					closeWindow.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e){
							interrupt();
							dispose();
						}
					});
				}
			}.start();
			syncProgress.setIndeterminate(false);
			final String path=syncPath;
			new Thread(){
				@Override
				public void run(){
					success=LivestockSolutions.syncBetweenDevice(path);
					MainFrame.getInstance().refreshTab();
					running = false;
				}
			}.start();
		}
	}
}
